process.env.TZ = 'Asia/Shanghai'; // 强制使用北京时间
// 在文件顶部添加缓存队列
let sensorCache = [];
let latestSensorData = null; // 存储最新传感器数据
let latestAlarm = null;
// 在 app.js 顶部导入 WebSocket
const WebSocket = require('ws');
const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const cors = require('cors');
const path = require('path');
const multer = require('multer');
const fs = require('fs');
const axios = require('axios');
const util = require('util'); // 用于安全打印对象
const { spawn } = require('child_process');

const app = express();
app.use(cors());
app.use(express.json());

const API_KEY = process.env.DASHSCOPE_API_KEY; // 如果未设置环境变量，使用硬编码
const APP_ID = '54d4f14b53574d75aa9fec68b74a07f7'; // 替换为你的实际 App ID

// === 修改点 1：数据库路径 ===
const dbPath = path.resolve(__dirname, 'memoryGame.db');
const db = new sqlite3.Database(dbPath, (err) => {
    if (err) {
        console.error('数据库连接失败:', err.message);
    } else {
        console.log(`成功连接数据库: ${dbPath}`);
        // 创建 Reminder 表（如果不存在）
        db.run(`
            CREATE TABLE IF NOT EXISTS Reminder (
                id INTEGER PRIMARY KEY,
                content TEXT NOT NULL,
                triggerTime TEXT NOT NULL,
                repeat TEXT NOT NULL,
                isCompleted INTEGER DEFAULT 0
            )
        `);
        // 在 Reminder 表创建后插入以下代码
        db.run(`
        CREATE TABLE  IF NOT EXISTS SensorData (
          id INTEGER PRIMARY KEY,
          temperature REAL NOT NULL,
          humidity REAL NOT NULL,
          presence BOOLEAN NOT NULL,
          movement INTEGER NOT NULL,
          breathing REAL NOT NULL,
          heart_rate REAL NOT NULL,
          smoke_level TEXT NOT NULL,
          humidifier_status TEXT NOT NULL,
          light_status TEXT NOT NULL,
          timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
        )
        `);
        // 添加索引加速查询
        db.run("CREATE INDEX IF NOT EXISTS idx_timestamp ON SensorData(timestamp DESC)");
        //添加控制指令数据库表
        db.run(`CREATE TABLE IF NOT EXISTS ControlCommands (
          id INTEGER PRIMARY KEY,
          device TEXT NOT NULL,
          action TEXT NOT NULL,
          timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
          processed INTEGER DEFAULT 0 
          )`);
    }
});

setInterval(() => {
  if (sensorCache.length === 0) return;
  const batch = [...sensorCache];
  sensorCache = [];

  const sql = `
    INSERT INTO SensorData (
      temperature, humidity, presence, movement, 
      breathing, heart_rate, smoke_level, 
      humidifier_status, light_status, timestamp
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?,?)
  `;
  
  db.serialize(() => {
    db.run("BEGIN TRANSACTION");
    batch.forEach(data => {
      const params = [
        data.temperature,
        data.humidity,
        data.presence ? 1 : 0,
        data.movement,
        data.breathing,
        data.heart_rate,
        data.smoke_level,
        data.humidifier_status,
        data.light_status,
        data.timestamp
      ];
      db.run(sql, params);
    });
    db.run("COMMIT", (err) => {
      if (err) console.error("批量写入失败:", err);
    });
  });
}, 5000); // 每5秒写入一次


// === 查询所有提醒事项 ===
app.get('/reminders', (req, res) => {
    const since = req.query.since;
    let sql = `SELECT id, content, triggerTime, repeat, isCompleted FROM Reminder`;
    let params = [];
    if (since) {
        // 1. 强制解析为服务器时区（如北京时间）
        const serverTime = new Date(since + ' UTC');
        const serverSince = serverTime.toISOString().slice(0, 19).replace('T', ' ');
        // 2. 使用 DATETIME() 函数确保时间比较正确
        sql += ` WHERE DATETIME(triggerTime) > DATETIME(?) ORDER BY triggerTime ASC`;
        params = [serverSince];
    } else {
        sql += ` ORDER BY triggerTime ASC`;
    }
    db.all(sql, params, (err, rows) => {
        if (err) return res.status(500).json({ error: err.message });
        // 对所有 triggerTime 字段进行格式化（确保返回格式统一）
        const formattedRows = rows.map(row => ({
            ...row,
            triggerTime: formatTriggerTime(row.triggerTime)
        }));
        res.json(formattedRows);
    });
});

function formatTriggerTime(dateTimeStr) {
    if (!dateTimeStr) return "";

    // 如果是 ISO 8601 格式（含 T）
    if (dateTimeStr.includes("T")) {
        const [datePart, timePart] = dateTimeStr.split("T");
        const [hours, minutes, seconds] = timePart.split(":");
        // 截断毫秒并补全秒数
        return `${datePart} ${hours}:${minutes}:${seconds || "00"}`;
    } else {
        // 如果是 YYYY-MM-DD HH:MM 格式，补全秒数
        if (dateTimeStr.split(" ").length === 1) {
            return `${dateTimeStr} 00:00:00`;
        } else if (dateTimeStr.split(":").length === 2) {
            return `${dateTimeStr}:00`;
        } else {
            // 截断毫秒（如果有）
            return dateTimeStr.split(".")[0];
        }
    }
}

// === 新增提醒（POST）===
app.post('/reminders', (req, res) => {
    const { id, content, triggerTime, repeat, isCompleted } = req.body;
    const formattedTime = formatTriggerTime(triggerTime);

    // 判断是否手动设置了 id
    if (id !== undefined && id !== null) {
        const sql = `
            INSERT INTO Reminder (id, content, triggerTime, repeat, isCompleted)
            VALUES (?, ?, ?, ?, ?)`;
        db.run(sql, [id, content, formattedTime, repeat, isCompleted ? 1 : 0], function(err) {
            if (err) return res.status(500).json({ error: err.message });
            res.json({ id });
        });
    } else {
        const sql = `
            INSERT INTO Reminder (content, triggerTime, repeat, isCompleted)
            VALUES (?, ?, ?, ?)`;
        db.run(sql, [content, formattedTime, repeat, isCompleted ? 1 : 0], function(err) {
            if (err) return res.status(500).json({ error: err.message });
            res.json({ id: this.lastID });
        });
    }
});

// === 更新提醒（PUT /reminders/:id）===
app.put('/reminders/:id', (req, res) => {
    const id = req.params.id;
    const { content, triggerTime, repeat, isCompleted } = req.body;
    const formattedTime = formatTriggerTime(triggerTime); // 使用新函数
    const sql = `
        UPDATE Reminder SET
        content = ?,
        triggerTime = ?,
        repeat = ?,
        isCompleted = ?
        WHERE id = ?`;

    db.run(sql, [content, formattedTime, repeat, isCompleted ? 1 : 0, id], function(err) {
        if (err) return res.status(500).json({ error: err.message });
        res.json({ changes: this.changes });
    });
});

// === 删除提醒（DELETE /reminders/:id）===
app.delete('/reminders/:id', (req, res) => {
    const id = req.params.id;
    const sql = `DELETE FROM Reminder WHERE id = ?`;

    db.run(sql, [id], function(err) {
        if (err) return res.status(500).json({ error: err.message });
        res.json({ changes: this.changes });
    });
});

//question
// === 查询所有题目（支持增量同步） ===
app.get('/questions', (req, res) => {
    const since = req.query.since;
    let sql = `SELECT id, type, content, choiceA, choiceB, choiceC, hint, is_custom, dynamic_rule, answer, grade FROM Question`;
    let params = [];
    if (since) {
        sql += ` WHERE id > ? ORDER BY id ASC`;
        params = [since];
    } else {
        sql += ` ORDER BY id ASC`;
    }
    db.all(sql, params, (err, rows) => {
        if (err) return res.status(500).json({ error: err.message });
        res.json(rows);
    });
});

// === 新增题目（POST /questions）===
app.post('/questions', (req, res) => {
    const { id, type, content, choiceA, choiceB, choiceC, hint, is_custom, dynamic_rule, answer, grade } = req.body;
    const sql = `
        INSERT INTO Question (
            id, type, content, choiceA, choiceB, choiceC, hint, is_custom, dynamic_rule, answer, grade
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `;
    db.run(sql, [id, type, content, choiceA, choiceB, choiceC, hint || null, is_custom ? 1 : 0, dynamic_rule || null, answer, grade], function(err) {
        if (err) return res.status(500).json({ error: err.message });
        res.json({ id });
    });
});

// === 更新题目（PUT /questions/:id）===
app.put('/questions/:id', (req, res) => {
    const id = req.params.id;
    const { type, content, choiceA, choiceB, choiceC, hint, is_custom, dynamic_rule, answer, grade } = req.body;
    const sql = `
        UPDATE Question SET
        type = ?, content = ?, choiceA = ?, choiceB = ?, choiceC = ?,
        hint = ?, is_custom = ?, dynamic_rule = ?, answer = ?, grade = ?
        WHERE id = ?
    `;
    db.run(sql, [type, content, choiceA, choiceB, choiceC, hint || null, is_custom ? 1 : 0, dynamic_rule || null, answer, grade, id], function(err) {
        if (err) return res.status(500).json({ error: err.message });
        res.json({ changes: this.changes });
    });
});

// === 删除题目（DELETE /questions/:id）===
app.delete('/questions/:id', (req, res) => {
    const id = req.params.id;
    const sql = `DELETE FROM Question WHERE id = ?`;
    db.run(sql, [id], function(err) {
        if (err) return res.status(500).json({ error: err.message });
        res.json({ changes: this.changes });
    });
});

// 配置 Multer 存储路径为宝塔的 videos 目录
function sanitizeFilename(filename) {
  if (!filename) return null;
  // 替换非法字符
  let safeName = filename.replace(/[<>:"/\\|?*\x00-\x1F]/g, '_');
  // 防止路径遍历攻击
  safeName = safeName.replace(/\.\.\//g, '_');
  return safeName;
}

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const uploadDir = '/www/wwwroot/html_test/videos';
    if (!fs.existsSync(uploadDir)) {
      fs.mkdirSync(uploadDir, { recursive: true });
    }
    cb(null, uploadDir);
  },
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname);
    // 从查询参数中获取自定义文件名（可选）
    let customFilename = req.query.filename;
    if (!customFilename) {
      customFilename = `webVideo-${Date.now()}`;
    } else {
      customFilename = sanitizeFilename(customFilename);
    }
    const filename = `${customFilename}${ext}`;
    cb(null, filename);
  }
});

// 限制文件大小和类型
const upload = multer({
  storage,
  limits: { fileSize: 200 * 1024 * 1024 }, // 200MB
  fileFilter: (req, file, cb) => {
    const allowedExtensions = ['.mp4', '.mov', '.avi'];
    const ext = path.extname(file.originalname).toLowerCase();
  
    if (allowedExtensions.includes(ext)) {
      cb(null, true);
    } else {
      cb(new Error('仅支持 MP4、MOV、AVI 格式的视频文件'));
    }
  }
});

app.post('/upload', upload.single('video'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: '未上传文件或文件类型不合法' });
  }

  // 返回视频访问地址
  const videoUrl = `http://47.109.75.129/videos/${req.file.filename}`;
  res.json({ videoUrl });
});

function generateThumbnail(filePath, thumbPath) {
  return new Promise((resolve, reject) => {
    const ffmpeg = spawn('ffmpeg', [
      '-i', filePath,
      '-ss', '00:00:01',
      '-vframes', '1',
      '-q:v', '2',
      thumbPath
    ]);

    ffmpeg.on('close', (code) => {
      if (code === 0) {
        resolve();
      } else {
        reject(new Error(`FFmpeg exited with code ${code}`));
      }
    });

    ffmpeg.stderr.on('data', (data) => {
      console.error(`FFmpeg stderr: ${data}`);
    });
  });
}

//获取视频时长
function getVideoDuration(filePath) {
  return new Promise((resolve, reject) => {
    const ffprobe = spawn('ffprobe', [
      '-v', 'error',
      '-show_entries', 'format=duration',
      '-of', 'csv=p=0', // 仅输出纯数字
      filePath
    ]);

    let duration = '';

    ffprobe.stdout.on('data', (data) => {
      const output = data.toString().trim();
      const match = output.match(/(\d+\.?\d*)/); // 提取数字部分
      if (match && match[1]) {
        duration = match[1]; // 仅保留数字
      }
    });

    ffprobe.on('close', (code) => {
      if (code === 0 && duration) {
        const seconds = parseFloat(duration);
        if (isNaN(seconds)) {
          console.error('解析视频时长失败：非数字输入', duration);
          reject(new Error('解析视频时长失败：无效的数值'));
          return;
        }

        const hours = Math.floor(seconds / 3600);
        const minutes = Math.floor((seconds % 3600) / 60);
        const secs = Math.floor(seconds % 60);
        const formattedDuration = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
        resolve(formattedDuration);
      } else {
        reject(new Error('获取视频时长失败'));
      }
    });

    ffprobe.stderr.on('data', (data) => {
      console.error(`ffprobe stderr: ${data}`);
    });
  });
}

// 获取视频列表
app.get('/videos', async (req, res) => {
  const videoDir = '/www/wwwroot/html_test/videos';
  const thumbnailDir = '/www/wwwroot/html_test/thumbnails';

  fs.readdir(videoDir, async (err, files) => {
    if (err) return res.status(500).json({ error: '读取视频目录失败' });

    const videos = [];

    for (const file of files) {
      if (!/(\.mp4|\.mov|\.avi)$/i.test(file)) continue;

      const filePath = path.join(videoDir, file);
      const thumbName = `${path.basename(file, path.extname(file))}.jpg`;
      const thumbPath = path.join(thumbnailDir, thumbName);

      if (!fs.existsSync(thumbPath)) {
        try {
          await generateThumbnail(filePath, thumbPath);
        } catch (err) {
          console.error(`生成缩略图失败: ${file}`, err);
        }
      }

      // 获取视频时长
      let duration = '00:00:00';
      try {
        duration = await getVideoDuration(filePath);
      } catch (err) {
        console.error(`获取时长失败: ${file}`, err);
      }

      videos.push({
        filename: file,
        url: `http://47.109.75.129/videos/${file}`,
        thumbnail: `http://47.109.75.129/thumbnails/${thumbName}`,
        duration: duration
      });
    }

    res.json(videos);
  });
});

//视频删除
app.delete('/videos/:filename', (req, res) => {
  const filename = req.params.filename;
  const filePath = `/www/wwwroot/html_test/videos/${filename}`;
  const thumbPath = `/www/wwwroot/html_test/thumbnails/${path.basename(filename, path.extname(filename))}.jpg`;

  fs.unlink(filePath, (err) => {
    if (err) return res.status(500).json({ error: '删除视频失败' });
    
    // 删除缩略图（如果存在）
    fs.unlink(thumbPath, () => {});
    
    res.json({ success: true });
  });
});

//视频重命名
function getBasename(filename) {
  const extIndex = filename.lastIndexOf('.');
  return extIndex > 0 ? filename.slice(0, extIndex) : filename;
}
// 重命名视频
app.post('/rename', (req, res) => {
  const oldName = req.body.oldName;
  const newName = req.body.newName;
  const videoDir = '/www/wwwroot/html_test/videos';
  const thumbnailDir = '/www/wwwroot/html_test/thumbnails';

  // 安全检查：防止路径遍历攻击
  if (!oldName || !newName || oldName.includes('..') || newName.includes('..')) {
    return res.status(400).json({ error: '非法文件名' });
  }

  const oldPath = path.join(videoDir, oldName);
  const newPath = path.join(videoDir, newName);

  fs.rename(oldPath, newPath, function (err) {
    if (err) return res.status(500).json({ error: '重命名视频失败' });

    // 重命名缩略图
    const oldThumb = getBasename(oldName) + '.jpg';
    const newThumb = getBasename(newName) + '.jpg';
    const oldThumbPath = path.join(thumbnailDir, oldThumb);
    const newThumbPath = path.join(thumbnailDir, newThumb);

    fs.rename(oldThumbPath, newThumbPath, function (err) {
      if (err && err.code !== 'ENOENT') {
        console.error('重命名视频失败:', err); // 打印错误详情
        console.warn('缩略图重命名失败:', err);
      }

      res.json({ success: true, message: '重命名成功' });
    });
  });
});

// =============================
// 新增：传感器数据接口
// =============================
// 修改时间格式化函数
function formatDateToLocal(date) {
  return date.toLocaleString('zh-CN', {
    timeZone: 'Asia/Shanghai',
    hour12: false,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit'
  }).replace(/\//g, '-');
}

// ===== 修改 /api/sensor/data 接口 =====
app.post('/api/sensor/data', (req, res) => {
  const data = req.body;
  
  // ✅ 强制校验除时间戳外的所有字段
  const requiredFields = [
    'temperature', 'humidity', 'presence', 'movement',
    'breathing', 'heart_rate', 'smoke_level', 
    'humidifier_status', 'light_status'
  ];
  
  // ❗️新增：提前定义 sensorData
  let sensorData = null;

  for (const field of requiredFields) {
    if (data[field] === undefined) {
      return res.status(400).json({ error: `缺少字段: ${field}` });
    }
  }

  // ✅ 严格使用服务器时间
  const serverTimestamp = new Date();
  const formattedTimestamp = formatDateToLocal(serverTimestamp);
  console.log("接收传感器数据，使用时间:", formattedTimestamp);

  // ✅ 新增：判断报警条件（示例：高烟雾或高心率）
    let alarmMessage = null;
        
    if (data.smoke_level === '高') {
        alarmMessage = `⚠️ 检测到高烟雾浓度（${data.humidity}%）`;
    } else if (data.heart_rate > 120) {
        alarmMessage = `⚠️ 检测到异常心率（${data.heart_rate} BPM）`;
    }

    // ✅ 构造传感器数据（强制使用服务器时间）
    sensorData = {
      ...data,
      movement: parseInt(data.movement),
      presence: Boolean(data.presence),
      timestamp: formattedTimestamp,
      ...(alarmMessage && { alarm: alarmMessage }) // 有报警信息时添加
  };


    // ✅ 显式更新全局报警状态
    if (alarmMessage) {
      latestAlarm = {
          message: alarmMessage,
          timestamp: new Date().toISOString(),
          source: 'sensor'
      };
    } else if (latestAlarm && latestAlarm.source === 'device') {
        // ❗️保留手动报警状态
    } else {
        latestAlarm = null; // ✅ 自动清除非手动报警
    }

  // ✅ 更新缓存和广播
  latestSensorData = sensorData;
  broadcastLatestSensorData(sensorData);
  sensorCache.push(sensorData);
  
  res.json({ status: 'cached' });
});

// 在文件末尾添加手动触发报警接口（建议放在其他 app.post 之后）
// 修改后的报警触发接口
app.post('/trigger-alarm', (req, res) => {
  const { message = '手动触发的紧急报警' } = req.body;
  
  // 保存报警状态到全局变量
  latestAlarm = {
      message: message.trim(),
      timestamp: new Date().toISOString(),
      source: 'device'
  };

    // 直接广播完整传感器数据 + 报警
    broadcastLatestSensorData({ 
      alarm: latestAlarm.message, // 强制传递报警字段
      source: latestAlarm.source // 关键修复：传递 source
    });
  
  res.json({
      status: 'success',
      message: '报警已广播',
      data: latestAlarm
  });
});

// 在 Reminder 路由之后插入
// 在 app.js 中添加时间范围查询参数
app.get('/api/sensor/history', (req, res) => {
  const { range = '24h' } = req.query;
  let timeFilter = '';
  
  // ✅ 时间范围验证
  const validRanges = ['24h', '7d', '30d'];
  if (!validRanges.includes(range)) {
    return res.status(400).json({ error: "无效的时间范围参数" });
  }

  // ✅ 构建时间过滤条件
  switch(range) {
    case '24h':
      timeFilter = `WHERE timestamp >= datetime('now', 'localtime', '-1 day')`;
      break;
    case '7d':
      timeFilter = `WHERE timestamp >= datetime('now', 'localtime', '-7 days')`;
      break;
    case '30d':
      timeFilter = `WHERE timestamp >= datetime('now', 'localtime', '-30 days')`;
      break;
  }

  // ✅ 强制降序排列并限制数量
  const sql = `
    SELECT * FROM SensorData 
    ${timeFilter} 
    ORDER BY timestamp DESC 
    LIMIT 50
  `;

  db.all(sql, (err, rows) => {
    if (err) {
      console.error("数据库查询失败:", err);
      return res.status(500).json({ 
        error: "数据库查询失败", 
        details: err.message 
      });
    }
    
    // ✅ 强制升序返回
    const sortedRows = rows.reverse();
    
    res.json(rows.map(row => ({
      ...row,
      presence: Boolean(row.presence),
      // ✅ 统一时间格式
      timestamp: row.timestamp.replace(' ', 'T')
    })));
  });
});


// 在 app.post('/api/control') 中添加推送函数
// 新增：广播传感器数据函数
// ✅ 修改广播函数：使用实时数据而非数据库
function broadcastLatestSensorData(newData) {
  const hasPresence = latestSensorData && latestSensorData.presence !== undefined;
  // 优先合并最新传感器数据
  const fullData = {
      ...latestSensorData, // 固定使用最新传感器数据
      ...newData,         // 覆盖报警字段
      presence: hasPresence ? Boolean(latestSensorData.presence) : false,
  };
  
  // 确保报警状态注入
  fullData.alarm = (latestAlarm && latestAlarm.message) || '无';
  
  wss.clients.forEach(client => {
      client.send(JSON.stringify(fullData));
  });
}

// 控制指令接口
// 修改 /api/control 接口
// === 修改后的控制接口 ===
app.post('/api/control', (req, res) => {
  const { device, action } = req.body;
  
  // ✅ 新增：将指令插入队列（这才是设备端能轮询到的）
  const insertSql = `INSERT INTO ControlCommands (device, action) VALUES (?, ?)`;
  db.run(insertSql, [device, action], function(err) {
    if (err) {
      console.error("插入控制指令失败:", err);
      return res.status(500).json({ error: "控制指令发送失败" });
    }
    
    // ✅ 删除原有的直接更新逻辑（因为设备端会处理状态更新）
    res.json({ status: "success" });
  });
});

// 新增：设备端更新设备状态接口
app.post('/api/device/status', (req, res) => {
  const { humidifier_status, light_status } = req.body;

  // 校验参数
  if (!humidifier_status && !light_status) {
    return res.status(400).json({ error: "缺少设备状态字段" });
  }

  // 构建更新语句
  const updates = [];
  const params = [];
  if (humidifier_status) {
    updates.push("humidifier_status = ?");
    params.push(humidifier_status);
  }
  if (light_status) {
    updates.push("light_status = ?");
    params.push(light_status);
  }

  const updateSql = `
    UPDATE SensorData 
    SET ${updates.join(', ')}
    WHERE id = (SELECT id FROM SensorData ORDER BY timestamp DESC LIMIT 1)
  `;

  db.run(updateSql, params, (err) => {
    if (err) {
      console.error("更新设备状态失败:", err);
      return res.status(500).json({ error: "设备状态更新失败" });
    }

    // 立即推送最新数据
    broadcastSensorData();
    res.json({ status: "success" });
  });
});

// 设备端轮询接口：获取最新未处理指令
app.get('/api/control/poll', (req, res) => {
  const sql = `SELECT * FROM ControlCommands WHERE processed = 0 ORDER BY timestamp DESC LIMIT 1`;
  db.get(sql, [], (err, row) => {
      if (err || !row) return res.json(null); // 无指令时返回 null
      res.json(row);
  });
});

// 设备端确认指令已处理
app.put('/api/control/:id', (req, res) => {
  const id = req.params.id;
  const sql = `UPDATE ControlCommands SET processed = 1 WHERE id = ?`;
  db.run(sql, [id], function(err) {
      if (err) return res.status(500).json({ error: err.message });
      res.json({ status: "success" });
  });
});

//AI API调用部分
app.post('/api/chat', async (req, res) => {
  const { message, sessionId } = req.body;

  const url = `https://dashscope.aliyuncs.com/api/v1/apps/${APP_ID}/completion`;

  try {
    const dashScopeResponse = await axios.post(url, {
      input: {
        prompt: message,
        session_id: sessionId
      },
      parameters: {
        incremental_output: 'true' // 启用增量输出
      }
    }, {
      headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Content-Type': 'application/json',
        'X-DashScope-SSE': 'enable' // 启用流式输出
      },
      responseType: 'stream' // 重要：处理为流
    });

    // 将阿里云的流式响应头传递给客户端
    res.header('Content-Type', 'text/event-stream');
    dashScopeResponse.data.pipe(res); // 将流式响应直接传给客户端

  } catch (error) {
    console.error(`Error calling DashScope: ${error.message}`);

    if (error.response) {
      console.error(`Status: ${error.response.status}`);
      console.error(`Response Data (safe): ${util.inspect(error.response.data, { depth: null, colors: true })}`);
    } else {
      console.error('No response from DashScope API');
    }

    // 返回 JSON 错误响应，而不是直接发送文本
    res.status(500).json({
      error: 'Internal Server Error',
      message: error.message,
      response: error.response && error.response.data ? error.response.data : null
    });
  }
});


// 启动服务
const PORT = 3000;
const server = app.listen(PORT, '0.0.0.0', () => {
  console.log(`服务运行在 http://0.0.0.0:${PORT}`);
});


// WebSocket 服务器在此处创建
const wss = new WebSocket.Server({ server });
wss.on('connection', (ws) => {
  // ✅ 新连接时立即发送最新数据
  if (latestSensorData) {
    ws.send(JSON.stringify({
      ...latestSensorData,
      presence: Boolean(latestSensorData.presence)
    }));
  }
});